<script setup lang="ts">
import {
  useMessage,
  NForm,
  NFormItem,
  NInput,
  NSelect,
  type FormInst,
  NButton,
  NDatePicker,
  NTreeSelect,
  NIcon,
  type TreeSelectOption,
  NConfigProvider,
  NAvatar,
  NUpload,
  NScrollbar,
  type UploadCustomRequestOptions,
  type UploadInst,
  NModal,
  NGrid,
  NGi,
  NDivider
} from 'naive-ui'
import { CloseCircle } from '@vicons/ionicons5'
import { onMounted, ref, reactive, shallowRef, nextTick, watch } from 'vue'
import { sendRequest } from '@/utils/api'
import type { UserInfoModel, UserPositionModel, PartyOrganizationModel } from '@/api/user'
import type { HttpResponse, HttpResponsePagination } from '@/utils/http'
import FixedAction from '@/components/FixedAction.vue'
import type { InstitutionTreeModel } from '@/api/sysInstitution'
import type { PositionTableRowModel } from '@/api/sysPosition'
import type { DicTreeModel } from '@/api/dic'
import { useRoute } from 'vue-router'
import { format } from 'date-fns'
import useRouteReplace from '@/hooks/useRouteReplace'
import { usePermissionStore } from '@/stores/permission'
import { cardNumberRegex } from '@/enums/regex'
import 'vue-cropper/dist/index.css'
import { VueCropper } from 'vue-cropper'

type Nullable<T> = { [P in keyof T]: T[P] | null }

const message = useMessage()
const route = useRoute()
const permissionStore = usePermissionStore()
const routeReplace = useRouteReplace(route.query.redirect as string)

const formInst = shallowRef<FormInst | null>(null)
const formData = ref({} as UserInfoModel)
const submitLoading = ref(false)

const rules = {
  accountName: {
    required: false,
    trigger: ['input', 'blur'],
    validator: (_: any, value: any) => {
      // if (value?.length > 10) return new Error('开户名 字数不得超过10')
      return true
    }
  },
  openingBank: {
    required: false,
    trigger: ['input', 'blur'],
    validator: (_: any, value: any) => {
      // if (value?.length > 100) return new Error('开户行 字数不得超过100')
      return true
    }
  },
  bankCardNumber: {
    required: false,
    trigger: ['input', 'blur'],
    validator: (_: any, value: any) => {
      return true
    }
  }
}

const handleSubmit = async () => {
  if (submitLoading.value) return
  formInst.value?.validate(async (error) => {
    if (error) return

    try {
      submitLoading.value = true
      const [error, res] = await sendRequest<HttpResponse<UserInfoModel>>({
        module: 'user',
        api: 'update',
        override: {
          data: {
            ...formData.value,
            carNumberList: formData.value.carNumberList.filter(Boolean)
          }
        }
      })

      if (error) return message.error(error.message)
      if (res.code !== 0) message.error(res.msg)
      window.flags.flushUser = true
      // 更新用户信息
      permissionStore.updateUserInfo()
      // 更新用户头像
      permissionStore.queryconfigINfoData()
      routeReplace()
    } catch (error) {
      console.log(error)
    } finally {
      submitLoading.value = false
    }
  })
}

// 职位列表
const positionList = shallowRef<PositionTableRowModel[]>([])
const queryPositionList = async () => {
  try {
    const [error, res] = await sendRequest<HttpResponsePagination<PositionTableRowModel>>({
      module: 'sysPosition',
      api: 'list',
      override: {
        params: {
          limit: 100000
        }
      }
    })

    if (error) return message.error(error.message)
    if (res.code !== 0) return message.error(res.msg)
    positionList.value = res.data.list
  } catch (error) {
    console.log(error)
  }
}

// 部门列表
const treeOptions = shallowRef<InstitutionTreeModel[]>([])
const treeLoading = ref(false)
const queryTreeOptions = async () => {
  try {
    treeLoading.value = true
    const [error, res] = await sendRequest<HttpResponse<InstitutionTreeModel[]>>({
      module: 'sysInstitution',
      api: 'getTree'
    })

    if (error) return message.error(error.message)
    if (res.code !== 0) return message.error(res.msg)
    treeOptions.value = res.data
  } catch (error) {
    console.log(error)
  } finally {
    treeLoading.value = false
  }
}
const deptOptions = ref<Nullable<Partial<UserPositionModel>>[]>([
  {
    deptId: null,
    positionId: null
  }
])
// @ts-ignore
formData.value.userPositionList = deptOptions.value

// 车牌号列表
const carNumberList = ref<(string | null)[]>([])
// @ts-ignore
formData.value.carNumberList = carNumberList.value
const handleAddCarNumber = () => {
  carNumberList.value.push(null)
}
const handleDeleteCarNumber = (index: number) => {
  carNumberList.value.splice(index, 1)
}

// 政治面貌
const politicalOptions = ref<DicTreeModel[] | undefined>()
const queryPoliticalOptions = async () => {
  const [error, res] = await sendRequest<HttpResponse<DicTreeModel[]>>({
    module: 'dic',
    api: 'getTree',
    override: {
      params: {
        dicCode: 'A22'
      }
    }
  })

  if (error) return message.error(error.message)
  if (res.code !== 0) return message.error(res.msg)
  politicalOptions.value = res.data[0]?.children
}

// 党职位
const partyPositionOptions = ref<DicTreeModel[] | undefined>()
const queryPartyPositionOptions = async () => {
  const [error, res] = await sendRequest<HttpResponse<DicTreeModel[]>>({
    module: 'dic',
    api: 'getTree',
    override: {
      params: {
        dicCode: 'A18'
      }
    }
  })

  if (error) return message.error(error.message)
  if (res.code !== 0) return message.error(res.msg)
  partyPositionOptions.value = res.data[0]?.children
}
// 党组织
const partyOrganizationOptions = ref<DicTreeModel[] | undefined>()
const queryPartyOrganizationOptions = async () => {
  const [error, res] = await sendRequest<HttpResponse<DicTreeModel[]>>({
    module: 'dic',
    api: 'getTree',
    override: {
      params: {
        dicCode: 'A17'
      }
    }
  })

  if (error) return message.error(error.message)
  if (res.code !== 0) return message.error(res.msg)
  partyOrganizationOptions.value = res.data[0]?.children
}

const userPartyList = ref<Nullable<Partial<PartyOrganizationModel>>[]>([])
// @ts-ignore
formData.value.userPartyList = userPartyList.value

const uploadInst = ref<UploadInst | null>(null)
const handleUpdateAvatar = async ({
  file,
  onFinish,
  onError,
  onProgress
}: UploadCustomRequestOptions) => {
  console.log(file)
  uploadInst.value?.clear()
  cropperImg.value = ''
  fileName.value = file.file?.name
  var reader = new FileReader()
  // 转化为base64
  reader.readAsDataURL(file.file as File)
  reader.onload = function () {
    cropperImg.value = reader.result as string
  }
  showCropper.value = true
  // const form = new FormData()
  // form.append('file', file.file as File)
  // try {
  //   const [error, res] = await sendRequest({
  //     module: 'upload',
  //     api: 'uploadFile',
  //     override: {
  //       data: form,
  //       onUploadProgress({ progress }) {
  //         onProgress({ percent: progress || 0 })
  //       }
  //     }
  //   })
  //   if (error) throw error
  //   if (res.code !== 0) throw new Error(res.msg)
  //   formData.value.headSculpture = res.data.url
  //   onFinish()
  // } catch (error: any) {
  //   onError()
  //   message.error(error.message)
  // }
}

const uploadAvatar = () => {
  return new Promise((resolve) => {
    const form = new FormData()
    cropper.value.getCropBlob(async (data: File) => {
      form.append('file', data as File, fileName.value)
      console.log('form: ', form)
      try {
        const [error, res] = await sendRequest({
          module: 'upload',
          api: 'uploadFile',
          override: {
            data: form,
            onUploadProgress({ progress }) {
              console.log('progress: ', progress)
            }
          }
        })
        if (error) throw error
        if (res.code !== 0) throw new Error(res.msg)
        formData.value.headSculpture = res.data.url
        resolve(res)
      } catch (error: any) {
        message.error(error.message)
      }
    })
  })
}
const queryUserInfo = async () => {
  formData.value = {} as UserInfoModel
  deptOptions.value = []
  carNumberList.value = []
  userPartyList.value = []

  try {
    const [error, res] = await sendRequest<HttpResponse<UserInfoModel>>({
      module: 'user',
      api: 'detailInfo',
      uri: {
        id: permissionStore.userInfo?.id!
      }
    })
    if (error) return message.error(error.message)
    if (res.code !== 0) return message.error(res.msg)
    if (res.data.partyTime) res.data.partyTime = format(new Date(res.data.partyTime), 'yyyy-MM-dd')
    if (res.data.birthday) res.data.birthday = format(new Date(res.data.birthday), 'yyyy-MM-dd')
    formData.value = {
      ...res.data
    }
    deptOptions.value = res.data.userPositionList
    carNumberList.value = res.data.carNumberList
    userPartyList.value = res.data.userPartyList
  } catch (error) {
    console.log(error)
  }
}

/**头像裁剪 */
const fileName = ref<string | undefined>('') // 保存fileName，自定义上传时需要该参数
const cropper = ref()
const cropperImg = ref<string>('')
const previews = ref({
  url: '',
  img: '',
  div: {},
  w: 0,
  h: 0
})
const previewScale = ref(1)
const showCropper = ref(false)
// 实时预览事件
const realTime = (data: any) => {
  console.log('data: ', data)
  previews.value = data
}
/**
 * 取消裁剪
 */
const cancelUpload = () => {
  showCropper.value = false
  fileName.value = ''
}
watch(
  () => previews.value.w,
  () => {
    previewScale.value = 200 / previews.value.w
  },
  { deep: true, immediate: true }
)

onMounted(() => {
  queryTreeOptions()
  queryPositionList()
  queryPoliticalOptions()
  queryPartyPositionOptions()
  queryPartyOrganizationOptions()
  queryUserInfo()
})
</script>

<template>
  <NConfigProvider
    abstract
    :theme-overrides="{
      Form: {
        labelTextColor: 'rgba(0,0,0,0.85)'
      }
    }"
  >
    <div class="add-user">
      <NScrollbar>
        <div class="form">
          <NForm
            :disabled="submitLoading"
            :model="formData"
            :rules="rules"
            ref="formInst"
            label-placement="left"
            require-mark-placement="left"
            label-width="100rem"
          >
            <NFormItem label="员工编号：">
              <NInput
                placeholder="/"
                :value="formData.userNumber"
                disabled
              />
            </NFormItem>
            <NFormItem
              label="姓名："
              class="name"
            >
              <NInput
                placeholder="请输入"
                v-model:value="formData.userName"
              />
            </NFormItem>
            <NFormItem
              label="性别："
              class="sex"
            >
              <NSelect
                v-model:value="formData.sex"
                :options="[
                  {
                    label: '男',
                    value: 1
                  },
                  {
                    label: '女',
                    value: 2
                  }
                ]"
              />
            </NFormItem>

            <NFormItem
              label="生日："
              class="birthday"
            >
              <NDatePicker
                input-readonly
                value-format="yyyy-MM-dd"
                v-model:formatted-value="formData.birthday"
              />
            </NFormItem>
            <!-- 开户名，开户行 -->
            <NDivider
              title-placement="left"
              style="--n-color: #5fb17f"
            >
              公务卡
            </NDivider>
            <div class="col2">
              <NFormItem
                label="开户名："
                path="accountName"
              >
                <NInput
                  placeholder="请输入"
                  v-model:value="formData.accountName"
                />
              </NFormItem>
              <NFormItem
                label="开户行："
                path="openingBank"
              >
                <NInput
                  placeholder="请输入"
                  v-model:value="formData.openingBank"
                />
              </NFormItem>
              <NFormItem
                label="银行卡号："
                path="bankCardNumber"
              >
                <NInput
                  placeholder="请输入"
                  v-model:value="formData.bankCardNumber"
                />
              </NFormItem>
            </div>
            <NDivider
              title-placement="left"
              style="--n-color: #5fb17f"
            >
              工资卡
            </NDivider>
            <div class="col2">
              <NFormItem
                label="开户名："
                path="payrollCardAccountName"
              >
                <NInput
                  placeholder="请输入"
                  v-model:value="formData.payrollCardAccountName"
                />
              </NFormItem>
              <NFormItem
                label="开户行："
                path="payrollCardBank"
              >
                <NInput
                  placeholder="请输入"
                  v-model:value="formData.payrollCardBank"
                />
              </NFormItem>
              <NFormItem
                label="银行卡号："
                path="payrollCardNumber"
              >
                <NInput
                  placeholder="请输入"
                  v-model:value="formData.payrollCardNumber"
                />
              </NFormItem>
            </div>
            <NDivider
              title-placement="left"
              style="--n-color: #5fb17f"
            >
              部门职位
            </NDivider>
            <div class="bg-wrapper">
              <div
                class="col2"
                v-for="(item, i) in deptOptions"
                :key="i"
              >
                <NFormItem label="部门：">
                  <NTreeSelect
                    disabled
                    :options="(treeOptions as unknown as TreeSelectOption[])"
                    placeholder="/"
                    key-field="id"
                    label-field="name"
                    :value="item.deptId"
                  />
                </NFormItem>
                <NFormItem label="职位：">
                  <NTreeSelect
                    disabled
                    :options="(positionList as unknown as TreeSelectOption[])"
                    placeholder="/"
                    key-field="id"
                    label-field="positionName"
                    :value="item.positionId"
                  />
                </NFormItem>
              </div>
            </div>
            <NDivider style="--n-color: #5fb17f"></NDivider>
            <NFormItem label="办公电话：">
              <NInput
                placeholder="请输入"
                v-model:value="formData.officePhone"
              />
            </NFormItem>

            <NFormItem label="手机号码：">
              <NInput
                placeholder="请输入"
                v-model:value="formData.phone"
              />
            </NFormItem>

            <NFormItem label="电子邮箱：">
              <NInput
                placeholder="请输入"
                v-model:value="formData.mail"
              />
            </NFormItem>

            <NFormItem label="车牌号：">
              <NButton
                color="#6CB187"
                ghost
                @click="handleAddCarNumber"
              >
                新增车牌号
              </NButton>
            </NFormItem>
            <div class="col2">
              <NFormItem
                label="车牌号："
                v-for="(_, i) in carNumberList"
                :key="i"
              >
                <NInput
                  placeholder="请输入"
                  v-model:value="carNumberList[i]"
                >
                  <template #suffix>
                    <NIcon
                      color="#fd4a29"
                      size="24rem"
                      style="cursor: pointer"
                      @click="handleDeleteCarNumber(i)"
                    >
                      <CloseCircle />
                    </NIcon>
                  </template>
                </NInput>
              </NFormItem>
            </div>

            <NFormItem label="头像：">
              <NUpload
                ref="uploadInst"
                :custom-request="handleUpdateAvatar"
                :accept="'image/*'"
                :max="1"
                abstract
              >
                <NButton
                  ghost
                  color="#5FB17F"
                  @click="uploadInst?.openOpenFileDialog()"
                >
                  修改头像
                </NButton>
              </NUpload>
            </NFormItem>
            <div class="avatar">
              <NAvatar
                style="margin-left: 100rem"
                :src="formData.headSculpture"
                :size="150"
              />
            </div>
          </NForm>
        </div>
      </NScrollbar>
    </div>
  </NConfigProvider>
  <n-modal
    v-model:show="showCropper"
    preset="dialog"
    title="修改头像"
    style="width: 60%"
    positive-text="确认"
    negative-text="取消"
    @positive-click="uploadAvatar"
    @negative-click="cancelUpload"
    @esc="cancelUpload"
    @mask-click="cancelUpload"
  >
    <div class="cropper-container">
      <n-grid
        x-gap="24"
        :cols="4"
      >
        <n-gi :span="3">
          <div>裁剪</div>
          <div class="vue-cropper">
            <vue-cropper
              autoCrop
              mode="contain"
              :img="cropperImg"
              ref="cropper"
              centerBox
              fixed
              :fixedNumber="[1, 1]"
              @realTime="realTime"
            />
          </div>
        </n-gi>
        <n-gi :span="1">
          <div>预览</div>
          <div
            class="preview-box"
            :style="{
              width: `${previews.w}px`,
              height: `${previews.h}px`,
              transform: `scale(${previewScale})`
            }"
          >
            <div :style="previews.div">
              <img
                :src="previews.url"
                :style="previews.img"
              />
            </div>
          </div>
          <!-- <div class="preview-box">
            <img
              v-if="previews.url"
              :src="previews.url"
              :style="previews.img"
            />
            <img
              v-else
              :src="formData.headSculpture"
              width="200"
              height="200"
            />
          </div> -->
        </n-gi>
      </n-grid>
    </div>
  </n-modal>
  <FixedAction>
    <div class="add-user-buttons">
      <NButton
        color="#999999"
        ghost
        :disabled="submitLoading"
        @click="routeReplace"
      >
        取消
      </NButton>

      <NButton
        color="#5FB17F"
        :disabled="submitLoading"
        :loading="submitLoading"
        @click="handleSubmit"
      >
        确定
      </NButton>
    </div>
  </FixedAction>
</template>

<style scoped lang="scss">
.add-user {
  flex: 1;
  padding: 25rem 56rem 110rem 36rem;
  width: 100%;
  height: 100%;
  overflow: hidden;

  .n-input,
  .n-tree-select,
  .n-date-picker,
  .n-select {
    width: 400rem;
  }

  .form {
    width: 100%;
    padding: 25rem 33rem 27rem 20rem;
    background-color: #ebeceb;

    .n-form {
      width: 70%;
      margin: 0 auto;
    }
  }

  .with-avatar {
    display: grid;
    grid-template-areas:
      'name avatar'
      'sex avatar'
      'birthday avatar';

    .name {
      grid-area: name;
    }

    .sex {
      grid-area: sex;
    }

    .birthday {
      grid-area: birthday;
    }

    .avatar {
      grid-area: avatar;
      align-self: center;
      justify-self: center;
      display: flex;
      align-items: flex-end;
      gap: 0 1em;
    }
  }

  .col2 {
    position: relative;
    display: grid;
    grid-template-columns: repeat(2, auto);
    gap: 0 60rem;

    .item-close {
      position: absolute;
      top: 5rem;
      right: -48rem;
      display: flex;
      align-items: center;
      font-size: 24rem;
      cursor: pointer;
      color: #fd4a29;
      transition: all ease-in-out 0.3s;

      &:hover {
        opacity: 0.8;
      }
    }
  }
}

.add-user-buttons {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0 16rem;

  .n-button {
    width: 100rem;
    height: 50rem;
  }
}

.cropper-container {
  display: flex;
  .vue-cropper {
    width: 100%;
    height: 580rem;
  }
  .preview-box {
    // margin: 0 auto;
    // width: 200px;
    // height: 200px;
    transform-origin: 0% 0%;
    border-radius: 10rem;
    border: 1px solid #ccc;
    overflow: hidden;
  }
}
</style>
